import time
import socket
import struct
from machine import RTC


class DateTime:
    # 　NTP 时间从 1900-01-01 00:00:00 UTC 开始计算，单位是秒
    # MicroPython 的 time 模块默认使用 Unix 时间戳（1970 年 1 月 1 日），单位是秒，相差70年
    NTP_DELTA = 2208988800  # (70*365 + 17)*86400 有17个闰年
    # ESP32 的底层 RTC 从 2000 年 1 月 1 日 开始计算，相差30年
    RTC_DELTA = 946684800  # (30*365 + 7)*86400 有7个闰年

    def __init__(self, timezone_offset=8):
        """初始化DateTime模块"""
        self.timezone_offset = timezone_offset
        self.rtc = RTC()
        self.ntp_servers = [
            "pool.ntp.org",
            "time.nist.gov",
            "cn.pool.ntp.org"
        ]

    def _ntp_request(self, host):
        """手动实现NTP请求（不依赖ntptime库）"""

        try:
            # 创建socket
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.settimeout(3)
            # 解析NTP服务器地址
            addr = socket.getaddrinfo(host, 123)[0][-1]
            # 发送NTP请求
            # NTP数据包格式：1字节LI=0(无警告) + 1字节VN=4 + 1字节Mode=3(客户端) + 47字节0
            packet = b'\x1b' + 47 * b'\0'
            s.sendto(packet, addr)
            # 接收响应
            data, _ = s.recvfrom(1024)
            s.close()
            # 解析响应，获取时间戳
            # NTP时间戳在数据的第40-43字节
            t = struct.unpack('!I', data[40:44])[0]
            return t - self.NTP_DELTA  # 转换为Unix时间

        except Exception as e:
            print(f"NTP请求失败: {str(e)}")
            return None

    def sync_time(self, max_retries=3):
        """从NTP服务器同步时间（使用手动NTP实现）"""
        # 尝试不同的NTP服务器
        for server in self.ntp_servers:
            retries = 0

            while retries < max_retries:
                try:
                    # 获取NTP时间(UTC)
                    utc_time = self._ntp_request(server)
                    if utc_time is None:
                        retries += 1
                        time.sleep(1)
                        continue
                    # 调整时区
                    local_time = utc_time + self.timezone_offset * 3600

                    # 转换为时间元组 (年, 月, 日, 时, 分, 秒, 星期, 儒略日)
                    tm = time.localtime(local_time - self.RTC_DELTA)
                    # tm格式: (年, 月, 日, 时, 分, 秒, 星期(0-6), 年中天数)
                    # 正确设置RTC
                    # RTC datetime格式: (年, 月, 日, 星期, 时, 分, 秒, 微秒)
                    # 星期转换: time.localtime返回0-6(周一到周日)，RTC通常使用1-7
                    self.rtc.datetime((
                        tm[0],  # 年
                        tm[1],  # 月
                        tm[2],  # 日
                        tm[6] + 1,  # 星期(转换为1-7)
                        tm[3],  # 时
                        tm[4],  # 分
                        tm[5],  # 秒
                        0  # 微秒
                    ))
                    print(f"时间同步成功 (服务器: {server}) -> {self.get_formatted_time()}")
                    return True

                except Exception as e:
                    retries += 1
                    print(f"同步失败 (服务器: {server}, 重试 {retries}/{max_retries}): {str(e)}")
                    time.sleep(1)

        print("所有NTP服务器均无法同步时间")
        return False

    def get_current_time(self):
        """获取当前时间元组"""
        return self.rtc.datetime()

    def get_formatted_time(self):
        """获取格式化的时间字符串"""
        dt = self.rtc.datetime()
        # dt格式: (年, 月, 日, 星期, 时, 分, 秒, 微秒)

        weekdays = ["一", "二", "三", "四", "五", "六", "日"]
        # 确保星期值在有效范围内
        if 1 <= dt[3] <= 7:
            weekday = weekdays[dt[3] - 1]
        else:
            weekday = "?"

        return f"{dt[0]}-{dt[1]:02d}-{dt[2]:02d} {dt[4]:02d}:{dt[5]:02d}:{dt[6]:02d} 星期{weekday}"

    def set_timezone(self, offset):
        """设置时区偏移"""
        self.timezone_offset = offset
        self.sync_time()

    def get_timestamp(self):
        """获取当前时间戳（Unix时间）"""
        dt = self.get_current_time()
        # 转换为time.localtime()兼容的格式
        tm = (dt[0], dt[1], dt[2], dt[4], dt[5], dt[6], dt[3] - 1, 0)
        return time.mktime(tm) - self.timezone_offset * 3600


# 使用示例
if __name__ == "__main__":
    datetime = DateTime(timezone_offset=8)

    if datetime.sync_time():
        print("当前时间:", datetime.get_formatted_time())
        print("RTC原始数据:", datetime.get_current_time())
        print("时间戳:", datetime.get_timestamp())
